package model

/*******************************************************************************
Copyright:cloud
Author:cloudapex@126.com
Version:1.0
Date:2020-07-07
Description: 用户模型
*******************************************************************************/

import (
	"errors"
	"fmt"

	"gitee.com/cloudapex/ulern/util"
	"xorm.io/xorm"
)

// => 用户表
type User struct {
	Id    int64  `json:"id" xorm:"pk"`
	CoId  int64  `json:"coId" xorm:"cid"`    // 所属公司ID
	Name  string `json:"name" xorm:"name"`   // 名称
	State int32  `json:"state" xorm:"state"` // 状态(1:正常;2:失效)

	CreatedAt util.TJsTime `json:"at" xorm:"at"`
	UpdatedAt util.TJsTime `json:"-" xorm:"update_at"`

	Sorte SortFinder `json:"-" xorm:"-"`
	Pager PageFinder `json:"-" xorm:"-"`
}

// => 用户与角色关联表
type UserRole struct {
	Id        int64
	UserId    int64        `xorm:"notnull index"` // 用户Id
	RoleId    int64        `xorm:"notnull index"` // 角色Id
	CreatedAt util.TJsTime `xorm:"created"`
}

// => 用户与用户组关联表
type UserGroup struct {
	Id        int64
	UserId    int64        `xorm:"notnull index"` // 用户Id
	GroupId   int64        `xorm:"notnull index"` // 用户组Id
	CreatedAt util.TJsTime `xorm:"created"`
}

// ----- User
func (this *User) TableName() string { return "staff_base" }

func (this *User) Load() (bool, error) {
	return MDB(EMDB_Permt).Get(this)
}
func (this *User) Create() (int64, error) {
	return MDB(EMDB_Permt).Insert(this)
}
func (this *User) Update(id int64, columns ...string) (int64, error) {
	return MDB(EMDB_Permt).ID(id).MustCols(columns...).Update(this)
}
func (this *User) Delete(id int64) (int64, error) {
	return MDB(EMDB_Permt).ID(id).Delete(&User{})
}
func (this *User) Orders() map[int]string {
	return map[int]string{1: "id", 2: "cid", 3: "at"}
}
func (this *User) condis(q *xorm.Session, tbl string) *xorm.Session {
	util.Cast(tbl != "", func() { tbl += "." }, nil)

	if this.Id != 0 {
		q = q.Where(fmt.Sprintf("%sid = ?", tbl), this.Id)
	}
	if this.CoId != 0 {
		q = q.Where(fmt.Sprintf("%scid = ?", tbl), this.CoId)
	}
	if this.Name != "" {
		q = q.Where(fmt.Sprintf("%sname like ?", tbl), "%"+this.Name+"%")
	}
	if this.State > 0 {
		q = q.Where(fmt.Sprintf("%sstate = ?", tbl), this.State)
	}
	return q
}
func (this *User) Find(scope ...string) (int32, []User, error) {
	dl := []User{}

	q := MDB(EMDB_Permt).Table(&User{})
	q = this.condis(q, "")
	q = this.Sorte.condis(q, "", "at", this.Orders())
	q = this.Pager.condis(q, &CTimeField{ETF_Unix, "at"}) // at

	q = q.Where(util.Stringv(scope))
	total, err := q.FindAndCount(&dl)
	return int32(total), dl, err
}

// ----- UserRole
func (this *UserRole) Insert(uId int64, rIds []int64) error {
	if len(rIds) == 0 {
		return nil
	}
	items := []UserRole{}
	for _, rId := range rIds {
		items = append(items, UserRole{UserId: uId, RoleId: rId})
	}
	for n := 0; ; n++ {
		end := (n + 1) * DEF_INSERT_BATCH_SIZE
		if end >= len(items) {
			end -= (end - len(items))
		}

		_, err := MDB(EMDB_Permt).Table(this).Insert(items[n*DEF_INSERT_BATCH_SIZE : end])
		if err != nil {
			return err
		}

		if end >= len(items) {
			break
		}
	}
	return nil
}
func (this *UserRole) Delete(uId, rId int64) (int64, error) {
	if uId == 0 && rId == 0 {
		return 0, errors.New("uId == 0 && rId == 0")
	}

	q := MDB(EMDB_Permt).Table(this)
	if uId != 0 {
		q = q.Where("user_id=?", uId)
	}
	if rId != 0 {
		q = q.Where("role_id=?", rId)
	}
	return q.Delete(&UserRole{})
}
func (this *UserRole) condis(q *xorm.Session, tbl string) *xorm.Session {
	util.Cast(tbl != "", func() { tbl += "." }, nil)

	if this.UserId != 0 {
		q.Where(fmt.Sprintf("%suser_id = ?", tbl), this.UserId)
	}
	if this.RoleId != 0 {
		q.Where(fmt.Sprintf("%srole_id = ?", tbl), this.RoleId)
	}
	return q
}
func (this *UserRole) FindIds() ([]int64, error) {
	ids := []int64{}

	q := MDB(EMDB_Permt).Table(this)

	util.Cast(this.UserId != 0, func() { q = q.Cols("role_id") }, nil)
	util.Cast(this.RoleId != 0, func() { q = q.Cols("user_id") }, nil)

	return ids, this.condis(q, "").Find(&ids)
}

// ----- UserGroup
func (this *UserGroup) Insert(uId int64, gIds []int64) error {
	if len(gIds) == 0 {
		return nil
	}

	items := []UserGroup{}
	for _, gId := range gIds {
		items = append(items, UserGroup{UserId: uId, GroupId: gId})
	}
	for n := 0; ; n++ {
		end := (n + 1) * DEF_INSERT_BATCH_SIZE
		if end >= len(items) {
			end -= (end - len(items))
		}

		_, err := MDB(EMDB_Permt).Table(this).Insert(items[n*DEF_INSERT_BATCH_SIZE : end])
		if err != nil {
			return err
		}

		if end >= len(items) {
			break
		}
	}
	return nil
}
func (this *UserGroup) Delete(uId, gId int64) (int64, error) {
	if uId == 0 && gId == 0 {
		return 0, errors.New("uId == 0 && gId == 0")
	}

	q := MDB(EMDB_Permt).Table(this)
	if uId != 0 {
		q = q.Where("user_id=?", uId)
	}
	if gId != 0 {
		q = q.Where("group_id=?", gId)
	}
	return q.Delete(&UserGroup{})
}
func (this *UserGroup) condis(q *xorm.Session, tbl string) *xorm.Session {
	util.Cast(tbl != "", func() { tbl += "." }, nil)

	if this.UserId != 0 {
		q.Where(fmt.Sprintf("%suser_id = ?", tbl), this.UserId)
	}
	if this.GroupId != 0 {
		q.Where(fmt.Sprintf("%sgroup_id = ?", tbl), this.GroupId)
	}
	return q
}
func (this *UserGroup) FindIds() ([]int64, error) {
	ids := []int64{}

	q := MDB(EMDB_Permt).Table(this)

	util.Cast(this.UserId != 0, func() { q = q.Cols("group_id") }, nil)
	util.Cast(this.GroupId != 0, func() { q = q.Cols("user_id") }, nil)

	return ids, this.condis(q, "").Find(&ids)
}

// ----- UserWithUserGroup
type UserWithUserGroup struct {
	User      `xorm:"extends"`
	UserGroup `xorm:"extends"`
	Sorte     SortFinder `json:"-" xorm:"-"`
	Pager     PageFinder `json:"-" xorm:"-"`
}

func (this *UserWithUserGroup) FindUsers(scope ...string) (int32, []User, error) {
	dl := []User{}
	x := MDB(EMDB_Permt)

	q := MDB(EMDB_Permt).Select(fmt.Sprintf("`%s`.*", x.TableName(&this.User)))
	q = q.Join("INNER", "user_group", fmt.Sprintf("%s.id = user_group.user_id", x.TableName(&this.User)))

	q = this.User.condis(q, x.TableName(&this.User))
	q = this.UserGroup.condis(q, "user_group")
	q = this.Sorte.condis(q, x.TableName(&this.User), "id", nil)
	q = this.Pager.condis(q, &CTimeField{ETF_Unix, fmt.Sprintf("%s.at", x.TableName(&this.User))})

	q = q.Where(util.Stringv(scope))
	total, err := q.GroupBy(fmt.Sprintf("%s.id", x.TableName(&this.User))).FindAndCount(&dl)
	return int32(total), dl, err
}
